﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using DapperHelper.Attributes;
using DapperHelper.Enums;
using DapperHelper.SqlBuilder;

namespace DapperHelper
{
    public class DapperHelper
    {
        public IDbConnection GetConnection(string connection, string dbProvider)
        {
            throw new Exception();
        }

        public IDataParameter GetParameter(string dbProvider, string pName, object pValue)
        {
            throw new Exception();
        }

        public int Insert<T>(string connection, string dbProvider, IEnumerable<T> tObjs)
        {
            int ret = 0;
            SqlBuilderFactory<T> factory = SqlBuilderFactory<T>.BuilderFactory;
            using (IDbConnection conn = GetConnection(connection, dbProvider))
            using (IDbTransaction transaction = conn.BeginTransaction())
            {
                conn.Open();
                ISqlBuilder<T> builder = factory.GetSqlBuilder(SqlType.Insert);
                string sql = builder.Build();
                foreach (T obj in tObjs)
                {
                    IDbCommand cmd = conn.CreateCommand();
                    cmd.CommandText = sql;
                    foreach (PropertyInfo prop in builder.GetObjectType().GetProperties())
                    {
                        string pName = $"@{builder.FieldName(prop)}";
                        object pVal = prop.GetValue(obj);
                        cmd.Parameters.Add(GetParameter(dbProvider, pName, pVal));
                    }
                    ret += cmd.ExecuteNonQuery();
                }
                transaction.Commit();
            }
            return ret;
        }

        public int Update<T>(string connection, string dbProvider, IEnumerable<T> tObjs)
        {
            int ret = 0;
            SqlBuilderFactory<T> factory = SqlBuilderFactory<T>.BuilderFactory;
            using (IDbConnection conn = GetConnection(connection, dbProvider))
            using (IDbTransaction transaction = conn.BeginTransaction())
            {
                conn.Open();
                ISqlBuilder<T> builder = factory.GetSqlBuilder(SqlType.Update);
                string sql = builder.Build();
                foreach (T obj in tObjs)
                {
                    IDbCommand cmd = conn.CreateCommand();
                    cmd.CommandText = sql;
                    foreach (PropertyInfo prop in builder.GetObjectType().GetProperties())
                    {
                        string pName = $"@{builder.FieldName(prop)}";
                        object pVal = prop.GetValue(obj);
                        cmd.Parameters.Add(GetParameter(dbProvider, pName, pVal));
                    }
                    ret += cmd.ExecuteNonQuery();
                }
                transaction.Commit();
            }
            return ret;
        }

        public int Delete<T>(string connection, string dbProvider, IEnumerable<T> tObjs)
        {
            int ret = 0;
            SqlBuilderFactory<T> factory = SqlBuilderFactory<T>.BuilderFactory;
            using (IDbConnection conn = GetConnection(connection, dbProvider))
            using (IDbTransaction transaction = conn.BeginTransaction())    
            {
                conn.Open();
                ISqlBuilder<T> builder = factory.GetSqlBuilder(SqlType.Delete);
                string sql = builder.Build();
                foreach (T obj in tObjs)
                {
                    IDbCommand cmd = conn.CreateCommand();
                    cmd.CommandText = sql;
                    foreach (PropertyInfo prop in builder.GetObjectType().GetProperties())
                    {
                        string pName = $"@{builder.FieldName(prop)}";
                        object pVal = prop.GetValue(obj);
                        cmd.Parameters.Add(GetParameter(dbProvider, pName, pVal));
                    }
                    ret += cmd.ExecuteNonQuery();
                }
                transaction.Commit();
            }
            return ret;
        }

        public IEnumerable<T> Query<T>(string connection, string dbProvider, 
            params Expression<Func<T, bool>>[] expressions)
        {
            IList<T> result = new List<T>();
            SqlBuilderFactory<T> factory = SqlBuilderFactory<T>.BuilderFactory;
            using (IDbConnection conn = GetConnection(connection, dbProvider))
            {
                conn.Open();
                ISqlBuilder<T> builder = factory.GetSqlBuilder(SqlType.Select);
                
            }

            return result;
        }
    }
}